<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use \Illuminate\Support\Collection;
use App\Observers\BaseModelObserver;
use Illuminate\Database\Eloquent\Concerns\HasEvents;
use App\Http\Extend\TraitLink;

class BaseModel extends Model
{
    use HasFactory, HasEvents, TraitLink;

    public static function boot()
    {
        parent::boot();
        self::observe(BaseModelObserver::class);
        // Setup event bindings...
    }
    /**
     * Safely escape a value
     *
     * @param  mixed       $value  value to escape
     * @return mixed|false escaped value or false if failed
     */
    public function escapeSql($value)
    {
        if (is_numeric($value)) {
            return is_string($value) ? "'" . addslashes($value) . "'" : $value;
        } elseif (is_null($value)) {
            return "NULL";
        } else {
            return "'" . addslashes($value) . "'";
        }
    }

    public function scopeSql($query)
    {
        $bindings = $query->getBindings();
        //过滤字符
        foreach ($bindings as $k => $v)
            $bindings[$k]  = $this->escapeSql($v);
        $sql = str_replace('?', '%s', $query->toSql());
        return sprintf($sql, ...$bindings);
    }

    public function scopeSearch($query, &$search)
    {

        return $query;
    }

    public function scopeRelatedJoin($query)
    {
    }

    public function scopeToSelect($query)
    {
        $array = [];
        $data = $query->get();
        foreach ($data as  $k => $v) {
            $array[$v['id']] = $v['name'];
        }
        return $array;
    }

    public static function scopeTreeGrid($query, $tree = false, $expanded = true, $loaded = true)
    {
        $data = $query->get();
        $treeGrids = [];
        $hasChild = function ($id) use ($data) {
            return  $data->filter(function ($value, $key) use ($id) {
                return $value['parent_id'] == $id;
            })->toArray();
        };
        $getTreeArray = function (array $nodes, $level) use (&$treeGrids, &$getTreeArray, $loaded, $expanded, $hasChild, $tree) {
            foreach ($nodes as $array) {
                $space = '';
                if ($tree)
                    $space = $level == 0
                        ? '&nbsp;'
                        : ($level == 1
                            ? '&nbsp;&nbsp;&nbsp;├'
                            : ($level == 2
                                ? '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;├'
                                : ($level == 3
                                    ? '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;├'
                                    : '')));
                $children = $hasChild($array['id']);

                $merge_array = [
                    'parent_id' => $array['parent_id'] === 0 ? null : $array['parent_id'],
                    'isLeaf' =>  $children == [] ? true : false,
                    'loaded' => $loaded,
                    'expanded' => $expanded,
                    'level' => $level,
                    'name' => $space . $array['name'],
                ];
                $treeGrids[] = array_merge($array, $merge_array);

                if ($children !== false) {
                    $getTreeArray($children, $level + 1);
                }
            }
        };

        $getTreeArray($hasChild(0), 0);
        return new Collection($treeGrids);
    }
    public function scopeGetGrid($query, $footers = [])
    {
        $totalsum = function ($footers = [], $sql = '', $totalField = '_total') {
            if (empty($footers)) {
                return [];
            }
            $fields = [];

            foreach ($footers as $key => $value) {
                if (is_string($value)) {
                    $fields[] = "CONVERT(SUM(" . $value . $totalField . "),DECIMAL(16,2)) AS {$value}";
                } else
                if (is_string($key)) {
                    $fields[] = "CONVERT(SUM(" . $key . $totalField . "),DECIMAL(16,2)) AS {$value}";
                }
            }

            $result = DB::table(DB::raw("(select " . implode(",", $fields) . " from ({$sql})tt) t"))->first();;

            return $result;
        };

        $loadonce = (int) post('loadonce') === 1;
        // 处理footer
        if (!empty($footers)) {
            foreach ($footers as $key => $value) {
                if (is_int($key)) {
                    $query->addSelect($value . ' as ' . $value . '_total');
                } else
            if (is_string($key)) {
                    $query->addSelect($key . " as " . $value . '_total');
                }
            }
        }

        $aggregateSql = $query->sql();
        // 总条数

        $countSql = "select count(*)as t_count from ({$aggregateSql})t";


        // 处理排序 
        $sortFieldName = post('sidx');
        //默认是  tablename.field
        $sortField = $query->getModel()->getTable() . "." . $sortFieldName;
        // 如果是left join  列是  creator.id as creator_id.
        //通过select 中的列。用as  分割成数组，用 creator_id 对比，获取creator.id  ，用creator.id 排序
        if ($query->getQuery()->columns)
            foreach ($query->getQuery()->columns as $v) {
                //DB::RAW 设置出的值，用getValue 取得列参数
                $v = !is_string($v) ? $v->getValue() : $v;
                $buf = explode(" as ", $v);
                //匹配到 creator_id 是排序用的名字，用creator.id 代替 sortField
                if (count($buf) > 1 && $buf['1'] == $sortFieldName) {
                    $sortField = DB::raw($buf[0]);
                }
            }
        $pagesize = post('rows');
        $page = max((int) post('page'), 1);
        $sortOrder = post('sord');

        $query
            ->when(!$loadonce, function ($query) use ($pagesize, $page) {
                $query->offset($pagesize * ($page - 1))->limit($pagesize);
            })
            ->when(!empty($sortField) && !$loadonce, function ($query) use ($sortField, $sortOrder) {
                $query->orderBy($sortField, $sortOrder);
            });

        $subtotalSql = $query->sql();

        $ajax['rows'] = DB::table(DB::raw("({$subtotalSql}) as t"))->get();

        $ajax['total'] = (int) DB::table(DB::raw("({$countSql}) as t"))->first()->t_count;
        $ajax['page'] = $page;
        $ajax['pagesize'] = (int) $pagesize;

        // 处理footer
        if (!empty($footers)) {
            $subtotal = $totalsum($footers, $subtotalSql);
            if (post('footerrow') > 1)
                $aggregate = $totalsum($footers, $aggregateSql);
            $ajax['userdata'] = array(
                $subtotal,
                $aggregate,
            );
        }
        $total = $ajax['total'];
        $pagesize = $ajax['pagesize'];

        $ajax['records'] = $total;
        $ajax['total'] = ceil($total / $pagesize);
        return new Collection($ajax);
    }
}
